#include "parser.h"
using namespace std;
Parser::Parser(): m_str(""), m_idx(0){

}
void Parser::load(const string & str){
    m_str = str;
    m_idx = 0;
}
void Parser::skip_white_space(){
    while(m_str[m_idx] == ' ' || m_str[m_idx] == '\n' || m_str[m_idx] == '\r' || m_str[m_idx] == '\t'){
        m_idx++;
    }
}
char Parser::get_next_token(){
    skip_white_space();
    return m_str[m_idx++];
}
Json Parser::parser(){
    char ch = get_next_token();
    switch (ch)
    {
    case 'n':
        m_idx--;
        return parse_null;
        break;
    case 't':
    case 'f':
        m_idx--;
        return parse_bool();
        break;
    case '-':
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
        m_idx--;
        return pasrse_number();
        break;
    case '"':
        return Json(parse_string());
        break;
    case '[':
        return parse_array();
        break;
    case '{':
        return parse_object();
        break;
    default:
        break;
    }
    perror("unexpected char");
}
Json Parser::parser(){
    if(m_str.compare(m_idx, 4, "null") == 0){
        m_idx += 4;
        return Json();
    }
    perror("parse null error");
}
Json Parser::parse_bool(){
    if(m_str.compare(m_idx, 4, "true") == 0){
        m_idx += 4;
        return Json(true);
    }else if(m_str.compare(m_idx, 5, "false") == 0){
        m_idx += 5;
        return Json(false);
    }
    perror("parse bool error");
}
Json Parser::pasrse_number(){
    int pos = m_idx;
    if(m_str[m_idx] == '-'){
        m_idx++;
    }
    if(m_str[m_idx] < '0' && m_str[m_idx] > '9'){
        perror("parse number error");
    }
    while(m_str[m_idx] >= '0' && m_str[m_idx] <= '9'){
        m_idx++;
    }
    if(m_str[m_idx] != '.'){
        int i = atoi(m_str.c_str()+pos);
        return Json(i);
    }
    m_idx++;
    if(m_str[m_idx] < '0' && m_str[m_idx] > '9'){
        perror("parse number error");
    }
    while(m_str[m_idx] >= '0' && m_str[m_idx] <= '9'){
        m_idx++;
    }
    double f= atof(m_str.c_str()+pos);
    return Json(f);
}
string Parser::parse_string(){
    string out;
    while(true){
        char ch = m_str[m_idx++];
        if(ch == '"'){
            break;
        }
        if(ch == '\\'){
            ch = m_str[m_idx++];
            switch (ch)
            {
            case '\n':
                out += '\n';
                break;
            case '\r':
                out += '\r';
                break;
            case '\t':
                out += '\t';
                break;
            case '\b':
                out += '\b';
                break;
            case '\f':
                out += '\f';
                break;
            case '"':
                out += "\\\"";
            case '\\':
                out += "\\\\";
            case 'u':
                out += '\\u';
                for(int i=0; i<4; i++){
                    out += m_str[m_idx++];
                }
            default:
                break;
            }
        }else{
            out += ch;
        }
        return out;
    }
}
Json Parser::parse_array(){
    Json arr(Json::json_array);
    char ch = get_next_token();
    if(ch == ']'){
        return arr;
    }
    while(1){
        arr.append(parser());
        ch = get_next_token();
        if(ch == ']'){
            break;
        }
        if(ch != ','){
            perror("parse array error");
        }
        m_idx++;
    }
    return arr;
}
Json Parser::parse_object(){
    Json object(Json::json_object);
    char ch = get_next_token();
    if(ch == ']'){
        return object;
    }
    m_idx--;
    while(1){
        ch = get_next_token();
        if(ch != '"'){
            perror("parse object error");
        }
        string key = parse_string();
        ch = get_next_token(); 
        if(ch != ':'){
            perror("parse object error");
        }
        object[key] = parser();
        ch = get_next_token();
        if(ch == '}'){
            break;
        }
        if(ch != ','){
            perror("parse object error");
        }
        m_idx++;
    }
    return object;
}